/*
 * Copyright (2022) Bytedance Ltd. and/or its affiliates
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <Catalog/DataModelPartWrapper_fwd.h>
#include <Interpreters/SystemLog.h>
#include <Storages/MergeTree/MergeTreeDataPartCNCH_fwd.h>

namespace DB
{
struct ServerPartLogElement
{
    enum Type
    {
        INSERT_PART = 1, // INSERT & ATTACH
        MERGE_PARTS = 2,
        MUTATE_PART = 3,
        DROP_RANGE = 4, /// ALTER ... DROP PARTITION/PART; exclude the drop marks generated by MERGE/MUTATE
        REMOVE_PART = 5, /// First phase in GC (Move metadata into trash).
        DELETE_PARTS = 6, /// Second phase in GC (erased from trash).
    };

    Type event_type = INSERT_PART;
    time_t event_time = 0;
    UInt64 txn_id = 0;

    String database_name;
    String table_name;
    UUID uuid;

    String part_name;
    String partition_id;
    // unique identifier for parts stored in object storage (S3)
    // empty for other storage (HDFS)
    String part_id;
    // whether the part is in staging area or not
    UInt8 is_staged_part = false;
    UInt64 rows = 0;
    UInt64 bytes = 0;
    // commit time of the txn adding the part
    UInt64 commit_ts = 0;
    // commit time of the txn removing the part
    // e.g, if part_a is covered by tombstone part_b, then end_ts(part_a) == commit_ts(part_b)
    // only REMOVE_PART will set this field
    UInt64 end_ts = 0;
    // source parts for MERGE_PARTS and MUTATE_PART
    // note that if a task mutates several parts in one txn, the source parts here is not
    // the input part for each new part, but all the source parts for the txn
    Strings source_part_names;

    UInt64 duration_ms = 0;
    UInt64 peak_memory_usage = 0;

    UInt8 from_attach = false;

    UInt8 error = 0;
    String exception;

    static std::string name() { return "ServerPartLog"; }
    static NamesAndTypesList getNamesAndTypes();
    static NamesAndAliases getNamesAndAliases();
    void appendToBlock(MutableColumns & columns) const;
};

class ServerPartLog : public SystemLog<ServerPartLogElement>
{
    using SystemLog<ServerPartLogElement>::SystemLog;
public:

    static bool addNewParts(
        const ContextPtr & local_context,
        StorageID storage_id,
        ServerPartLogElement::Type type,
        const MutableMergeTreeDataPartsCNCHVector & parts,
        const MutableMergeTreeDataPartsCNCHVector & staged_parts,
        UInt64 txn_id,
        UInt8 error,
        const Strings & source_part_names = {},
        UInt64 duration_ns = 0,
        UInt64 peak_memory_usage = 0,
        bool from_attach = false);

    static bool addRemoveParts(
        const ContextPtr & local_context,
        StorageID storage_id,
        const ServerDataPartsVector & parts,
        bool is_staged);

    static bool addDeleteParts(const ContextPtr & local_context, StorageID storage_id, const ServerDataPartsVector & parts);

    void prepareTable() override;
};

}
